﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BlobAnalyticsClient.cs" company="">
//   
// </copyright>
// <summary>
//   The blob analytics client.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace XRay.Library
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    using AutoMapper;

    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Analytics;
    using Microsoft.WindowsAzure.Storage.Blob;
    using Microsoft.WindowsAzure.Storage.Shared.Protocol;
    using Microsoft.WindowsAzure.Storage.Table;

    using XRay.Library.Contracts;

    /// <summary>
    ///     The blob analytics client.
    /// </summary>
    public class BlobAnalyticsClient : AnalyticsClientBase
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="BlobAnalyticsClient"/> class.
        /// </summary>
        /// <param name="cloudStorageAccount">
        /// The cloud storage account.
        /// </param>
        /// <param name="location">
        /// The location.
        /// </param>
        public BlobAnalyticsClient(CloudStorageAccount cloudStorageAccount, StorageLocation location)
            : base(cloudStorageAccount, StorageService.Blob, location)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BlobAnalyticsClient"/> class.
        /// </summary>
        /// <param name="cloudStorageAccount">
        /// The cloud storage account.
        /// </param>
        public BlobAnalyticsClient(CloudStorageAccount cloudStorageAccount)
            : base(cloudStorageAccount, StorageService.Blob, StorageLocation.Primary)
        {
            Mapper.CreateMap<CapacityEntity, BlobCapacity>()
                .ForMember(dest => dest.Timestamp, expression => expression.ResolveUsing<TimestampResolver>())
                .ForMember(
                    dest => dest.CapacityDataFor, 
                    expression => expression.ResolveUsing<CapacityDataForResolver>());
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The get capacity.
        /// </summary>
        /// <param name="start">
        /// The start.
        /// </param>
        /// <param name="end">
        /// The end.
        /// </param>
        /// <returns>
        /// The <see cref="IEnumerable"/>.
        /// </returns>
        public override IEnumerable<BlobCapacity> GetCapacity(DateTimeOffset start, DateTimeOffset end)
        {
            return this.GetCapacityAsync(start, end, CancellationToken.None).Result;
        }

        /// <summary>
        /// The get capacity async.
        /// </summary>
        /// <param name="start">
        /// The start.
        /// </param>
        /// <param name="end">
        /// The end.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public override async Task<IEnumerable<BlobCapacity>> GetCapacityAsync(
            DateTimeOffset start, 
            DateTimeOffset end, 
            CancellationToken cancellationToken)
        {
            var filter =
                TableQuery.CombineFilters(
                    TableQuery.GenerateFilterCondition(
                        "PartitionKey", 
                        QueryComparisons.GreaterThanOrEqual, 
                        start.ToString("yyyyMMddT0000")), 
                    TableOperators.And, 
                    TableQuery.GenerateFilterCondition(
                        "PartitionKey", 
                        QueryComparisons.LessThanOrEqual, 
                        end.ToString("yyyyMMddT0000")));

            var tableQuery = new TableQuery<CapacityEntity>().Where(filter);

            var table = this.cloudStorageAccount.CreateCloudAnalyticsClient().GetCapacityTable();

            var results = await this.QueryTableAsync(table, tableQuery, cancellationToken);

            return results.Select(Mapper.Map<CapacityEntity, BlobCapacity>);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The get service properties async.
        /// </summary>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        protected override async Task<ServiceProperties> GetServicePropertiesAsync(CancellationToken cancellationToken)
        {
            var blobClientClient = this.cloudStorageAccount.CreateCloudBlobClient();
            return
                await
                blobClientClient.GetServicePropertiesAsync(
                    new BlobRequestOptions { RetryPolicy = this.azureStorageRetryPolicy }, 
                    null, 
                    cancellationToken);
        }

        /// <summary>
        /// The set service properties async.
        /// </summary>
        /// <param name="properties">
        /// The properties.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        protected override async Task SetServicePropertiesAsync(
            ServiceProperties properties, 
            CancellationToken cancellationToken)
        {
            var blobClientClient = this.cloudStorageAccount.CreateCloudBlobClient();
            await
                blobClientClient.SetServicePropertiesAsync(
                    properties,
                    new BlobRequestOptions { RetryPolicy = this.azureStorageRetryPolicy },
                    null,
                    cancellationToken);
        }

        #endregion
    }
}